package com.zz.client.handle.defaults;

import com.zz.client.config.ChannelCache;
import com.zz.common.annotation.Executor;
import com.zz.common.config.Constants;
import com.zz.common.entity.Information;
import com.zz.common.entity.Meta;
import com.zz.common.entity.ProtocolInfo;
import com.zz.common.enums.MessageType;
import com.zz.common.enums.SerializationType;
import com.zz.common.exception.TunnelException;
import com.zz.common.handle.executor.AbstractMessageExecutor;
import com.zz.common.protocol.DefaultProtocol;
import com.zz.common.utils.ObjectUtil;
import com.zz.common.utils.SnowflakeUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

/**
 * 断开连接
 */
@Slf4j
@Executor(msgType = MessageType.TYPE_DISCONNECT)
public class DisconnectedExecutor extends AbstractMessageExecutor {


    @Override
    public void execute(Information information) {
        ChannelHandlerContext context = information.getContext();
        Channel localChannel = context.channel().attr(Constants.Attributes.LOCAL_CHANNEL).getAndSet(Constants.Objects.CHANNEL_NULL);
        if (ObjectUtil.isNotNull(localChannel)) {
            localChannel.attr(Constants.Attributes.SERVER_CHANNEL).set(Constants.Objects.CHANNEL_NULL);
            localChannel.close();
        }
        ChannelCache.addSalveServerChannel(context.channel());
    }

    @Override
    public void execute(ProtocolInfo protocolInfo) {
        Channel serverChannel = protocolInfo.getServerChannel();
        Meta meta = protocolInfo.getContext().channel().attr(Constants.Attributes.META).get();
        if (ObjectUtil.isNull(meta)) {
            log.error("client connect error, meta is null");
            throw new TunnelException("元数据为空");
        }
        // 构建断开连接消息
        DefaultProtocol protocolMsg = DefaultProtocol.builder().type(protocolInfo.getType())
                .serialNumber(SnowflakeUtil.genSnowflakeId())
                .serializationType(SerializationType.PROTOSTUFF)
                .meta(meta)
                .build();
        serverChannel.writeAndFlush(protocolMsg).addListener(future -> {
            ObjectUtil.setFieldNull(serverChannel, Constants.Attributes.LOCAL_CHANNEL);
            ChannelCache.addSalveServerChannel(serverChannel);
        });
        ObjectUtil.setFieldNull(protocolInfo.getContext(), Constants.Attributes.META, Constants.Attributes.SERVER_CHANNEL);
        protocolInfo.getContext().channel().close();
    }
}
